import tkinter as tk
import os
import time
import copy
import numpy as np

from cnn_gobang.config import GameConfig, GameData

# 定义窗口
top = tk.Tk()
top.title("智能五子棋-重构版")
top.geometry('400x500')

# 定义画布
canvas = tk.Canvas(top, height=GameConfig.map_size * GameConfig.pix_size,
                   width=GameConfig.map_size * GameConfig.pix_size, bg="gray")
canvas.pack(pady=10)


def init_board_lines():
    for i in range(GameConfig.map_size):
        canvas.create_line(i * GameConfig.pix_size, 0, i * GameConfig.pix_size,
                           GameConfig.map_size * GameConfig.pix_size,
                           fill='black')
        canvas.create_line(0, i * GameConfig.pix_size, GameConfig.map_size * GameConfig.pix_size,
                           i * GameConfig.pix_size,
                           fill='black')


def init_game_board():
    # 初始棋盘
    for i in range(GameConfig.map_size):
        stepRow = []
        blackRow = []
        whiteRow = []
        for j in range(GameConfig.map_size):
            stepRow.append(0)
            blackRow.append(GameConfig.empty_code)
            whiteRow.append(GameConfig.empty_code)
        GameData.blackBoard.append(blackRow)
        GameData.whiteBoard.append(whiteRow)
        GameData.stepBoard.append(stepRow)


def Restart():
    for child in GameData.childMap:
        canvas.delete(child)
    GameData.childMap.clear()
    GameData.isGameOver = False
    GameData.IsTurnWhite = True
    GameData.mapRecords1.clear()
    GameData.mapRecords2.clear()
    GameData.stepRecords1.clear()
    GameData.stepRecords2.clear()
    GameData.scoreRecords1.clear()
    GameData.scoreRecords2.clear()

    # 注意whiteBoard和blackBoard不能重新创建，否则自动训练异常
    for i in range(GameConfig.map_size):
        for j in range(GameConfig.map_size):
            GameData.whiteBoard[j][i] = GameConfig.empty_code
            GameData.blackBoard[j][i] = GameConfig.empty_code

    # init_game_board()


# 获得赢棋方 1白 -1黑 0游戏中
def JudgementResult():
    judge_map = GameData.whiteBoard
    for i in range(GameConfig.map_size):
        for j in range(GameConfig.map_size):
            if judge_map[j][i] != GameConfig.empty_code:
                point_tag = judge_map[j][i]
                check_row = True
                check_col = True
                check_line = True
                check_line2 = True
                for k in range(GameConfig.win_set - 1):
                    if i + k + 1 < GameConfig.map_size:  # 行
                        if (judge_map[j][i + k + 1] != point_tag) and check_row:
                            check_row = False
                        if j + k + 1 < GameConfig.map_size:  # 斜线
                            if (judge_map[j + k + 1][i + k + 1] != point_tag) and check_line:
                                check_line = False
                        else:
                            check_line = False
                    else:
                        check_row = False
                        check_line = False
                    if j + k + 1 < GameConfig.map_size:  # 列
                        if (judge_map[j + k + 1][i] != point_tag) and check_col:
                            check_col = False
                        if i - k - 1 >= 0:  # 斜线
                            if (judge_map[j + k + 1][i - k - 1] != point_tag) and check_line2:
                                check_line2 = False
                        else:
                            check_line2 = False
                    else:
                        check_col = False
                        check_line2 = False
                    if not check_row and not check_col and not check_line and not check_line2:
                        break
                if check_row or check_col or check_line or check_line2:
                    if GameData.AutoPlayTimes == 0:
                        print(str(point_tag) + 'win')
                        print('game over! x2')
                    GameData.isGameOver = True
                    GameData.TrainNet(point_tag)
                    return point_tag
    return 0


# 人工下棋事件
def playChessEvent(event):
    if GameData.isGameOver:
        print('game is over, restart! x01')
        Restart()
        return
    point_x = event.x // GameConfig.pix_size
    point_y = event.y // GameConfig.pix_size
    if point_x >= GameConfig.map_size or point_y >= GameConfig.map_size:
        return
    if GameData.whiteBoard[point_y][point_x] != GameConfig.empty_code:
        return
    score = 0
    if GameData.PlayWithComputer is not None:
        _x, _y, score = GameData.PlayWithComputer()
    res = chess_point(point_x, point_y, score)

    # 游戏未结束，电脑下棋
    if res == 0 and GameData.PlayWithComputer is not None:
        point_x, point_y, score = GameData.PlayWithComputer()
        chess_point(point_x, point_y, score)


def chess_point(point_x, point_y, score):
    # 当前是否由白棋走
    if GameData.isGameOver:
        if GameData.AutoPlayTimes == 0:
            print('game is over, restart! x02')
        Restart()
        return -1
    if GameData.whiteBoard[point_y][point_x] != GameConfig.empty_code:
        if GameData.AutoPlayTimes == 0:
            print('game is over, restart! x03')
        Restart()
        return -1
    step = copy.deepcopy(GameData.stepBoard)
    step[point_y][point_x] = 1
    if GameData.IsTurnWhite:  # 白棋是人工走的 如果过用来当训练集 用反转棋盘
        GameData.mapRecords1.append(copy.deepcopy(GameData.blackBoard))
        GameData.stepRecords1.append(step)
        GameData.scoreRecords1.append(score)
        GameData.whiteBoard[point_y][point_x] = GameConfig.white_code  # 1白 -1黑
        GameData.blackBoard[point_y][point_x] = GameConfig.black_code
        child = canvas.create_oval(point_x * GameConfig.pix_size,
                                   point_y * GameConfig.pix_size,
                                   point_x * GameConfig.pix_size + GameConfig.pix_size,
                                   point_y * GameConfig.pix_size + GameConfig.pix_size, fill='white')
    else:
        GameData.mapRecords2.append(copy.deepcopy(GameData.whiteBoard))
        GameData.stepRecords2.append(step)
        GameData.scoreRecords2.append(score)
        GameData.whiteBoard[point_y][point_x] = GameConfig.black_code  # 1白 -1黑
        GameData.blackBoard[point_y][point_x] = GameConfig.white_code
        child = canvas.create_oval(point_x * GameConfig.pix_size,
                                   point_y * GameConfig.pix_size,
                                   point_x * GameConfig.pix_size + GameConfig.pix_size,
                                   point_y * GameConfig.pix_size + GameConfig.pix_size, fill='black')
    GameData.childMap.append(child)
    GameData.IsTurnWhite = not GameData.IsTurnWhite
    return JudgementResult()


# 添加按钮
def ReAutoPlayTimes():
    GameData.AutoPlayTimes += 1000
    while GameData.AutoPlayTimes > 0:
        res = 0
        while res == 0:
            point_x, point_y, score = GameData.PlayWithComputer()
            res = chess_point(point_x, point_y, score)

        GameData.AutoPlayTimes -= 1
        chess_point(point_x, point_y, score)
        point_x, point_y, score = GameData.PlayWithComputer()
        res = chess_point(point_x, point_y, score)


# 添加按钮
def AutoPlayOnce():
    if GameData.PlayWithComputer is not None:
        point_x, point_y, score = GameData.PlayWithComputer()
        chess_point(point_x, point_y, score)


def setGameBtn():
    btn_auto_play = tk.Button(top, text="自动训练加开始1000次", command=ReAutoPlayTimes)
    btn_auto_play.pack()

    btn_auto = tk.Button(top, text="自动走1次", command=AutoPlayOnce)
    btn_auto.pack()

    # 画布与鼠标左键进行绑定
    canvas.bind("<Button-1>", playChessEvent)


def getBoards():
    # np.array将列表转为数组
    boardArr = []
    if GameData.IsTurnWhite:
        boardArr = np.array(GameData.blackBoard)
    else:
        boardArr = np.array(GameData.whiteBoard)
    boards = []
    for i in range(GameConfig.map_size):
        for j in range(GameConfig.map_size):
            if boardArr[j][i] == GameConfig.empty_code:
                boardTemp = np.copy(boardArr)
                boardTemp[j][i] = GameConfig.black_code
                boards.append(boardTemp)
    return boards


def getPositions():
    # np.array将列表转为数组
    boardArr = []
    if GameData.IsTurnWhite:
        boardArr = np.array(GameData.blackBoard)
    else:
        boardArr = np.array(GameData.whiteBoard)
    positions = []
    for i in range(GameConfig.map_size):
        for j in range(GameConfig.map_size):
            if boardArr[j][i] == GameConfig.empty_code:
                positions.append([i, j])
    return positions


# 显示游戏窗口
def ShowWind():
    init_game_board()
    init_board_lines()

    setGameBtn()
    top.mainloop()
